package com.tanhua.sso.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.common.mapper.UserMapper;
import com.tanhua.common.pojo.User;
import com.tanhua.dubbo.server.api.DashboardApi;
import com.tanhua.dubbo.server.api.HuanXinApi;
import com.tanhua.dubbo.server.api.ManageFreezeApi;
import com.tanhua.dubbo.server.enums.FreezingRangeEnum;
import com.tanhua.sso.config.AliyunSMSConfig;
import com.tanhua.sso.vo.ErrorResult;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class SmsService {

    @Reference(version = "1.0.0")
    private HuanXinApi huanXinApi;

    @Reference(version = "1.0.0")
    private ManageFreezeApi manageFreezeApi;

    @Autowired
    private AliyunSMSConfig aliyunSMSConfig;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private UserMapper userMapper;

    @Value("${jwt.secret}")
    private String secret;

    @Reference(version = "1.0.0")
    private DashboardApi dashboardApi;


    //使用阿里云第三方接口，发送验证码
    public String sendSms(String mobile) {
        DefaultProfile profile = DefaultProfile.getProfile(this.aliyunSMSConfig.getRegionId(),
                this.aliyunSMSConfig.getAccessKeyId(), this.aliyunSMSConfig.getAccessKeySecret());
        IAcsClient client = new DefaultAcsClient(profile);

        String code = RandomUtils.nextInt(100000, 999999) + "";

        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain(this.aliyunSMSConfig.getDomain());
        request.setSysVersion("2017-05-25");
        request.setSysAction("SendSms");
        request.putQueryParameter("RegionId", this.aliyunSMSConfig.getRegionId());
        request.putQueryParameter("PhoneNumbers", mobile); //目标手机号
        request.putQueryParameter("SignName", this.aliyunSMSConfig.getSignName()); //签名名称
        request.putQueryParameter("TemplateCode", this.aliyunSMSConfig.getTemplateCode()); //短信模板code
        request.putQueryParameter("TemplateParam", "{\"code\":\"" + code + "\"}");//模板中变量替换
        try {
            CommonResponse response = client.getCommonResponse(request);
            String data = response.getData();
            if (StringUtils.contains(data, "\"Message\":\"OK\"")) {
                return code;
            }
            log.info("发送短信验证码失败~ data = " + data);
        } catch (Exception e) {
            log.error("发送短信验证码失败~ mobile = " + mobile, e);
        }
        return null;
    }


    /**
     * 实现功能：发送验证码，使用第三方接口
     *
     * @param phone
     * @return
     */
    public ErrorResult getCheckCode(String phone) {
        //1.判断验证码是否未失效
        String redisKey = "CHECK_CODE_" + phone;
        if (redisTemplate.hasKey(redisKey)) {
            return ErrorResult.builder().errMessage("验证码未失效!").errCode("10001").build();
        }
        //发送验证码,阿里云没钱了，使用默认的验证码123456
        //String code = this.sendSms(phone);
        String code = "123456";
        //验证码是否为空
        if (StringUtils.isEmpty(code)) {
            return ErrorResult.builder().errMessage("发送验证码失败，验证码结果为空").errCode("10001").build();
        }
        //将验证码写入redis缓存中,并设置超时时间1分钟
        redisTemplate.opsForValue().set(redisKey, code, Duration.ofMinutes(1));
        return null;
    }

    /**
     * 实现功能:验证码是否正确
     *
     * @param phone
     * @param verificationCode
     * @return
     */
    public HashMap<String, Object> loginVerification(String phone, String verificationCode) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        Boolean isNew = false;
        String token = null;
        //1.校验redis缓存中是否有该手机正确的验证码
        String redisKey = "CHECK_CODE_" + phone;
        if (!StringUtils.equals(redisTemplate.opsForValue().get(redisKey), verificationCode)) {
            log.error("验证码校验失败,缓存中没有对应的验证码信息!");
            return null;
        }
        //2.判断该手机号是否是老用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("mobile", phone);
        User user = userMapper.selectOne(wrapper);
        if (user == null) {
            //1.该手机号是新用户,注册该手机用户
            user = new User();
            user.setMobile(phone);
            user.setPassword("123456");
            //保存新用户
            userMapper.insert(user);


            //注册环信用户
            Boolean result = this.huanXinApi.register(user.getId());
            if (!result) {
                //注册环信失败，记录日志
                log.error("注册环信用户失败~ userId = " + user.getId());
            }


            isNew = true;
        }


        /**
         * 登录成功后,开始写登录日志表
         */

        //3.生成token设置过期时间
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        token = Jwts.builder()
                .setClaims(claims) //payload，存放数据的位置，不能放置敏感数据，如：密码等
                .signWith(SignatureAlgorithm.HS256, secret) //设置加密方法和加密盐
                .setExpiration(new DateTime().plusHours(12).toDate()) //设置过期时间，12小时后过期
                .compact();
        //3.返回包含token的结果,isNew表示新老用户
        map.put("token", token);
        map.put("isNew", isNew);
        return map;
    }

    /**
     * 保存日志
     *
     * @param request
     * @param userId
     */
    public void saveLog(HttpServletRequest request, Long userId) {

        //获取登录用户主机名称
        String hostName = request.getRemoteHost();

        dashboardApi.saveUserLog(userId, hostName);

    }


    /**
     * 判断是否冻结状态
     *
     * @param phone
     * @return
     */
    public Boolean stateFrozen(String phone) {
        Boolean accountState = false;
        if (StrUtil.isNotEmpty(phone)) {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("mobile", phone);
            //查找用户信息
            User user = userMapper.selectOne(wrapper);

            //判断冻结状态
            accountState = manageFreezeApi.isAccountState(Convert.toInt(user.getId()),FreezingRangeEnum.REGISTER);
        }

        return accountState;
    }
}
